/**
 * @file bm77spp03.c
 * @brief bt io driver
 *
 * @author lbx@witsi.cn
 * @date 2014-5-4
 */
 
#include "dev.h"
#include <key.h>
#include <sys/ioctl.h>
#include "arch.h"
#include "init.h"
#include "syscfg.h"
#include "iodev.h"
#include "config.h"
#include "kernel.h"
#include "dev.h"

#ifdef BT_MODE_CTR_PRO
static int bt_run_mode;
#endif

typedef enum{
	BT_STAUS_SHUTDOWN = 0x1001,
	BT_STAUS_ACCESS,
	BT_STAUS_LINK,
}bt_status_t;

#ifdef BT_STATUS_IO_PRO
#define get_status() ( (gpio_input(BT_STATUS2_GPIO) | \
					(gpio_input(BT_STATUS_GPIO)<<1) )& 0x3)					
#endif

#ifdef BT_MODE_CTR_PRO
#define bt_mode_app()	do{\
        bt_run_mode = 0;\
		gpio_output(BT_MODE_EAN_GPIO, 0);\
		gpio_output(BT_MODE_P24_GPIO, 1);\
		gpio_output(BT_MODE_P20_GPIO, 1);\
	}while(0)
#define bt_mode_test()	do{\
        bt_run_mode = 1;\
		gpio_output(BT_MODE_EAN_GPIO, 0);\
		gpio_output(BT_MODE_P24_GPIO, 1);\
		gpio_output(BT_MODE_P20_GPIO, 0);\
	}while(0)
#define bt_mode_boot()	do{\
        bt_run_mode = 2;\
		gpio_output(BT_MODE_EAN_GPIO, 1);\
		gpio_output(BT_MODE_P24_GPIO, 0);\
		gpio_output(BT_MODE_P20_GPIO, 0);\
	}while(0)
#endif

void bt_io_disable(void)
{	
#if (CONFIG_BT_UART == 3)
    SYSCFG->CLK_GATE0 &= ~UART3_CLK_EN;
  	SYSCFG->PIN_MUXING1 &= ~TXD3_RXD3_PIN_EN;  
	SYSCFG->PIN_MUXING1 |= GPIO69_70_EN;
#endif	

	gpio_set_output(69, 0);//rxd
	gpio_output(69, 0);
	gpio_set_output(70, 0);//txd
	gpio_output(70, 0);

#ifdef BT_STATUS_IO_PRO
	gpio_set_output(BT_STATUS_GPIO, 0);
	gpio_set_output(BT_STATUS2_GPIO, 0);
	gpio_output(BT_STATUS_GPIO, 0);
	gpio_output(BT_STATUS2_GPIO, 0);
#endif

#ifndef BT_SIMP_IO_PRO
	#ifdef BT_CTS_IO_PRO
	gpio_set_output(BT_CTS_GPIO, 0);
	gpio_output(BT_CTS_GPIO, 0);
	gpio_set_output(BT_RTS_GPIO, 0);
	gpio_output(BT_RTS_GPIO, 0);
	#endif
	gpio_set_output(BT_PAIRING_GPIO, 0);
	gpio_output(BT_PAIRING_GPIO, 0);

	gpio_set_output(BT_LINK_DROP_GPIO, 0);
	gpio_output(BT_LINK_DROP_GPIO, 0);

	gpio_set_output(BT_WAKE_UP_GPIO, 0);
	gpio_output(BT_WAKE_UP_GPIO, 0);

	gpio_set_output(BT_RX_IND_GPIO, 0);
	gpio_output(BT_RX_IND_GPIO, 0);
#endif

#ifdef BT_MODE_CTR_PRO
	gpio_output(BT_MODE_EAN_GPIO, 0);
	gpio_output(BT_MODE_P24_GPIO, 0);
	gpio_output(BT_MODE_P20_GPIO, 0);
#endif

}

void bt_io_enable(void)
{	
#if (CONFIG_BT_UART == 3)
    SYSCFG->PIN_MUXING1 &= ~GPIO69_70_EN;  
	SYSCFG->PIN_MUXING1 |= TXD3_RXD3_PIN_EN;
	SYSCFG->CLK_GATE0 |= UART3_CLK_EN;
#endif

#ifdef BT_STATUS_IO_PRO
	gpio_set_input(BT_STATUS_GPIO, 0);
	gpio_set_input(BT_STATUS2_GPIO, 0);
#endif
	
#ifndef BT_SIMP_IO_PRO
	#ifdef BT_CTS_IO_PRO
	gpio_set_output(BT_CTS_GPIO, 0);
	gpio_output(BT_CTS_GPIO, 1);
	gpio_set_output(BT_RTS_GPIO, 0);
	gpio_output(BT_RTS_GPIO, 0);
	#endif
	gpio_set_output(BT_PAIRING_GPIO, 0);
	gpio_output(BT_PAIRING_GPIO, 1);

	gpio_set_output(BT_LINK_DROP_GPIO, 0);
	gpio_output(BT_LINK_DROP_GPIO, 1);

	gpio_set_output(BT_WAKE_UP_GPIO, 1);
	gpio_output(BT_WAKE_UP_GPIO, 1);

	gpio_set_output(BT_RX_IND_GPIO, 0);
	gpio_output(BT_RX_IND_GPIO, 0);
#endif		

#ifdef BT_MODE_CTR_PRO
    if(bt_run_mode == 0)
		bt_mode_app();
	else if(bt_run_mode == 1)
		bt_mode_test();
	else if(bt_run_mode == 2)
		bt_mode_boot();
#endif    
}

static int bt_power_state = 0;
static int bak_bt_power_state = 0;
static void bt_enable(void)
{
	bt_power_state = 1;

	bt_io_enable();
	mdelay(10);
	gpio_set_output(BT_POWER_GPIO, 0);
	gpio_output(BT_POWER_GPIO, 0);
}

static void bt_disable(void)
{
	bt_power_state = 0;
	
	gpio_set_output(BT_POWER_GPIO, 0);
	gpio_output(BT_POWER_GPIO, 1);	
	bt_io_disable();
}

static int bm77spp03_init(iodev_t *dev)
{	
#ifdef BT_MODE_CTR_PRO
    gpio_set_output(BT_MODE_EAN_GPIO, 0);
    gpio_set_output(BT_MODE_P24_GPIO, 1);
    gpio_set_output(BT_MODE_P20_GPIO, 1);
    bt_mode_test();
#endif    
	bt_disable();
    mdelay(10);
	bt_enable();
    mdelay(500); 

	return 0;
}

static int bm77spp03_ioctl(iodev_t *dev, uint32_t cmd, void *arg)
{
	int ret = 0;
	uint32_t mode;
						
	switch (cmd) {
    	case IOCTL_GET_BT_STATUS:
#ifdef BT_STATUS_IO_PRO
            if (!bt_power_state) {
                ret = BT_STAUS_SHUTDOWN;
	            break;
            }
            
	    	switch(get_status()){
				case 3:
					ret = BT_STAUS_SHUTDOWN;
	        		break;
				case 2:
					ret = BT_STAUS_ACCESS;
	        		break;
				case 1:
				case 0:
					ret = BT_STAUS_LINK;
	        		break;
	    	}
#else
			ret = BT_STAUS_SHUTDOWN + bt_power_state;
#endif
			break;
			
		case IOCTL_BT_ADV:
			bt_enable();
			break;
			
		case IOCTL_BT_LINK_DROP:
			bt_disable();
			mdelay(200);
			break;
			
		case IOCTL_BT_WAKE_UP:
			bt_enable();
			mdelay(10);
			break;
			
		case IOCTL_BT_MODE_CTL:
#ifdef BT_MODE_CTR_PRO            
			mode = (uint32_t)arg;
			if(mode > 2)
				return -1;

            if (mode == bt_run_mode)
                break;
            
			bt_disable();
			mdelay(200);
			if(mode == 0)
				bt_mode_app();
			else if(mode == 1)
				bt_mode_test();
			else if(mode == 2)
				bt_mode_boot();
            
			mdelay(10);
			bt_enable();
			mdelay(650);
#else            
            ret = -1;
#endif            
			break;
    }
    return ret;
}

static int bm77spp03_suspend(iodev_t *dev,int sleep)
{
	if (sleep > 0) {
		bak_bt_power_state = bt_power_state;
        bt_disable();
    }
	
    return 0;
}

static int bm77spp03_wakeup(iodev_t *dev, int sleep)
{
   if ( sleep > 0) {
   		if(bak_bt_power_state)
			bt_enable();
   }
   return 0;
}

static const iodev_t bt_bm77spp03 __iodev_entry = {
        .name = "bt",
        .priv = NULL,
        .init = bm77spp03_init,
        .read = NULL,
        .write = NULL,
        .ioctl = bm77spp03_ioctl,
        .poll = NULL,
#ifdef CONFIG_POWER_CTL
        .suspend = bm77spp03_suspend,
        .wakeup = bm77spp03_wakeup,
#endif
};

